home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / QuickTime VR / MacOS / QuickDraw™ 3D 1.0.6F4 SDK / Samples / SampleCode / BoxTex / BoxTex3DSupport.c < prev    next >
Encoding:
Text File  |  1995-06-08  |  15.6 KB  |  581 lines  |  [TEXT/MPCC]

  1. // Quickdraw 3D sample code
  2. //
  3. // This file contains utility routines for QuickDraw 3d sample code.
  4. // This app shows how to apply a texture shader to an object.  Bear in
  5. // mind that any object that you wish to texture map needs to have
  6. // UV parameters applied.
  7. //
  8. // Nick Thompson, AppleLink: DEVSUPPORT (devsupport@applelink.apple.com)
  9. //
  10. // ©1994-5 Apple Computer Inc., All Rights Reserved
  11.  
  12.  
  13.  
  14. #include <QuickDraw.h>
  15. #include <QDOffScreen.h>
  16. #include <Files.h>
  17.  
  18.  
  19. #include "BoxTex3DSupport.h"
  20.  
  21.  
  22. #include "QD3DDrawContext.h"
  23. #include "QD3DRenderer.h"
  24. #include "QD3DShader.h"
  25. #include "QD3DCamera.h"
  26. #include "QD3DLight.h"
  27. #include "QD3DGeometry.h"
  28. #include "QD3DGroup.h"
  29. #include "QD3DMath.h"
  30. #include "QD3DSet.h"
  31. #include "QD3DTransform.h"
  32.  
  33. #include "Textures.h"
  34.  
  35.  
  36. static     TQ3Point3D    documentGroupCenter;
  37. static    float        documentGroupScale;
  38.  
  39.  
  40. static    TQ3FileObject         MyGetNewFile( FSSpec *myFSSpec, TQ3Boolean *isText ) ;
  41.  
  42. void GetGroupBBox(
  43.     DocumentPtr            theDocument,
  44.     TQ3BoundingBox         *viewBBox) ;
  45.                                                 
  46. static    TQ3Status MyAddShaderToGroup( TQ3GroupObject group ) ;
  47.  
  48. static TQ3Status GetDocumentGroupBoundingBox( 
  49.     DocumentPtr theDocument , 
  50.     TQ3BoundingBox *viewBBox) ;
  51.  
  52. //----------------------------------------------------------------------------------
  53. // attach a shader to the group
  54.  
  55. static TQ3Status MyAddShaderToGroup( TQ3GroupObject group )
  56. {
  57. //    TQ3ShaderObject    illuminationShader = Q3PhongIllumination_New();
  58.     TQ3ShaderObject    illuminationShader = Q3LambertIllumination_New();
  59.  
  60.     Q3Group_AddObject(group, illuminationShader);
  61.     Q3Object_Dispose(illuminationShader);
  62.     return(kQ3Success);
  63. }
  64.  
  65. TQ3ViewObject MyNewView(WindowPtr theWindow)
  66. {
  67.     TQ3Status                myStatus;
  68.     TQ3ViewObject            myView;
  69.     TQ3DrawContextObject        myDrawContext;
  70.     TQ3RendererObject        myRenderer;
  71.     TQ3CameraObject            myCamera;
  72.     TQ3GroupObject            myLights;
  73.     
  74.     myView = Q3View_New();
  75.     
  76.     //    Create and set draw context.
  77.     if ((myDrawContext = MyNewDrawContext(theWindow)) == nil )
  78.         goto bail;
  79.         
  80.     if ((myStatus = Q3View_SetDrawContext(myView, myDrawContext)) == kQ3Failure )
  81.         goto bail;
  82.  
  83.     Q3Object_Dispose( myDrawContext ) ;
  84.     
  85.     //    Create and set renderer.
  86.     
  87.     
  88.     
  89.     // this would use the wireframe renderer
  90. #if 0
  91.     myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  92.     if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  93.         goto bail;
  94.     }
  95. #else
  96.     // this would use the interactive software renderer
  97.  
  98.     if ((myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive)) != nil ) {
  99.         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  100.             goto bail;
  101.         }
  102.     }
  103.     else {
  104.         goto bail;
  105.     }
  106. #endif
  107.  
  108.     Q3Object_Dispose( myRenderer ) ;
  109.     
  110.     //    Create and set camera.
  111.     if ( (myCamera = MyNewCamera(theWindow)) == nil )
  112.         goto bail;
  113.         
  114.     if ((myStatus = Q3View_SetCamera(myView, myCamera)) == kQ3Failure )
  115.         goto bail;
  116.  
  117.     Q3Object_Dispose( myCamera ) ;
  118.     
  119.     //    Create and set lights.
  120.     if ((myLights = MyNewLights()) == nil )
  121.         goto bail;
  122.         
  123.     if ((myStatus = Q3View_SetLightGroup(myView, myLights)) == kQ3Failure )
  124.         goto bail;
  125.         
  126.     Q3Object_Dispose(myLights);
  127.  
  128.     //    Done!!!
  129.     return ( myView );
  130.     
  131. bail:
  132.     //    If any of the above failed, then don't return a view.
  133.     return ( nil );
  134. }
  135.  
  136. //----------------------------------------------------------------------------------
  137.  
  138. TQ3DrawContextObject MyNewDrawContext(WindowPtr theWindow)
  139. {
  140.     TQ3DrawContextData        myDrawContextData;
  141.     TQ3MacDrawContextData    myMacDrawContextData;
  142.     TQ3ColorARGB            ClearColor;
  143.     TQ3DrawContextObject    myDrawContext ;
  144.     
  145.     //    Set the background color.
  146.     ClearColor.a = 1.0;
  147.     ClearColor.r = 1.0;
  148.     ClearColor.g = 1.0;
  149.     ClearColor.b = 1.0;
  150.     
  151.     //    Fill in draw context data.
  152.     myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor;
  153.     myDrawContextData.clearImageColor = ClearColor;
  154.     myDrawContextData.paneState = kQ3False;
  155.     myDrawContextData.maskState = kQ3False;
  156.     myDrawContextData.doubleBufferState = kQ3True;
  157.  
  158.     myMacDrawContextData.drawContextData = myDrawContextData;
  159.     
  160.     myMacDrawContextData.window = (CGrafPtr) theWindow;        // this is the window associated with the view
  161.     myMacDrawContextData.library = kQ3Mac2DLibraryNone;
  162.     myMacDrawContextData.viewPort = nil;
  163.     myMacDrawContextData.grafPort = nil;
  164.     
  165.     //    Create draw context and return it, if it’s nil the caller must handle
  166.     myDrawContext = Q3MacDrawContext_New(&myMacDrawContextData) ;
  167.  
  168.     return myDrawContext ;
  169. }
  170.  
  171. //----------------------------------------------------------------------------------
  172.  
  173. TQ3CameraObject MyNewCamera(WindowPtr theWindow)
  174. {
  175.     TQ3ViewAngleAspectCameraData    perspectiveData;
  176.     TQ3CameraObject                camera;
  177.     
  178.     TQ3Point3D                     from     = { 0.0, 0.0, 13.0 };
  179.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  180.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  181.  
  182.     float                         fieldOfView = 1;
  183.     float                         hither         =  0.001;
  184.     float                         yon         =  1000;
  185.     
  186.     TQ3Status                    returnVal = kQ3Failure ;
  187.  
  188.  
  189.     perspectiveData.cameraData.placement.cameraLocation     = from;
  190.     perspectiveData.cameraData.placement.pointOfInterest     = to;
  191.     perspectiveData.cameraData.placement.upVector             = up;
  192.  
  193.     perspectiveData.cameraData.range.hither    = hither;
  194.     perspectiveData.cameraData.range.yon     = yon;
  195.  
  196.     perspectiveData.cameraData.viewPort.origin.x = -1.0;
  197.     perspectiveData.cameraData.viewPort.origin.y = 1.0;
  198.     perspectiveData.cameraData.viewPort.width = 2.0;
  199.     perspectiveData.cameraData.viewPort.height = 2.0;
  200.     
  201.     perspectiveData.fov                = fieldOfView;
  202.     perspectiveData.aspectRatioXToY    =
  203.         (float) (theWindow->portRect.right - theWindow->portRect.left) / 
  204.         (float) (theWindow->portRect.bottom - theWindow->portRect.top);
  205.         
  206.     camera = Q3ViewAngleAspectCamera_New(&perspectiveData);
  207.  
  208.     return camera ;
  209. }
  210.  
  211.  
  212. //----------------------------------------------------------------------------------
  213.  
  214. TQ3GroupObject MyNewLights()
  215. {
  216.     TQ3GroupPosition            myGroupPosition;
  217.     TQ3GroupObject            myLightList;
  218.     TQ3LightData                myLightData;
  219.     TQ3PointLightData        myPointLightData;
  220.     TQ3DirectionalLightData    myDirectionalLightData;
  221.     TQ3LightObject            myAmbientLight, myPointLight, myFillLight;
  222.     TQ3Point3D                pointLocation = { -10.0, 0.0, 10.0 };
  223.     TQ3Vector3D                fillDirection = { 10.0, 0.0, 10.0 };
  224.     TQ3ColorRGB                WhiteLight = { 1.0, 1.0, 1.0 };
  225.     
  226.     //    Set up light data for ambient light.  This light data will be used for point and fill
  227.     //    light also.
  228.  
  229.     myLightData.isOn = kQ3True;
  230.     myLightData.color = WhiteLight;
  231.     
  232.     //    Create ambient light.
  233.     myLightData.brightness = .2;
  234.     myAmbientLight = Q3AmbientLight_New(&myLightData);
  235.     if ( myAmbientLight == nil )
  236.         goto bail;
  237.     
  238.     //    Create point light.
  239.     myLightData.brightness = 1.0;
  240.     myPointLightData.lightData = myLightData;
  241.     myPointLightData.castsShadows = kQ3False;
  242.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  243.     myPointLightData.location = pointLocation;
  244.     myPointLight = Q3PointLight_New(&myPointLightData);
  245.     if ( myPointLight == nil )
  246.         goto bail;
  247.  
  248.     //    Create fill light.
  249.     myLightData.brightness = .2;
  250.     myDirectionalLightData.lightData = myLightData;
  251.     myDirectionalLightData.castsShadows = kQ3False;
  252.     myDirectionalLightData.direction = fillDirection;
  253.     myFillLight = Q3DirectionalLight_New(&myDirectionalLightData);
  254.     if ( myFillLight == nil )
  255.         goto bail;
  256.  
  257.     //    Create light group and add each of the lights into the group.
  258.     myLightList = Q3LightGroup_New();
  259.     if ( myLightList == nil )
  260.         goto bail;
  261.     myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
  262.     if ( myGroupPosition == 0 )
  263.         goto bail;
  264.     myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
  265.     if ( myGroupPosition == 0 )
  266.         goto bail;
  267.     myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
  268.     if ( myGroupPosition == 0 )
  269.         goto bail;
  270.  
  271.     Q3Object_Dispose( myAmbientLight ) ;
  272.     Q3Object_Dispose( myPointLight ) ;
  273.     Q3Object_Dispose( myFillLight ) ;
  274.  
  275.     //    Done!
  276.     return ( myLightList );
  277.     
  278. bail:
  279.     //    If any of the above failed, then return nothing!
  280.     return ( nil );
  281. }
  282.  
  283.  
  284. static TQ3GroupPosition MyAddTransformedObjectToGroup( TQ3GroupObject theGroup, TQ3Object theObject, TQ3Vector3D *translation )
  285. {
  286.     TQ3TransformObject    transform;
  287.  
  288.     transform = Q3TranslateTransform_New(translation);
  289.     Q3Group_AddObject(theGroup, transform);    
  290.     Q3Object_Dispose(transform);
  291.     return Q3Group_AddObject(theGroup, theObject);    
  292. }
  293.  
  294. TQ3GroupObject MyNewModel()
  295. {
  296.     TQ3GroupObject            myGroup = NULL;
  297.     TQ3GeometryObject        myBox;
  298.     TQ3BoxData                myBoxData;
  299.     TQ3ShaderObject            myIlluminationShader ;
  300.     TQ3Vector3D                translation;
  301.     
  302.     if ((myGroup = Q3DisplayGroup_New()) != NULL ) {
  303.         
  304.         MyAddShaderToGroup( myGroup ) ;
  305.     
  306.         // Define a shading type for the group
  307.         // and add the shader to the group
  308.     
  309.         myIlluminationShader = Q3PhongIllumination_New();
  310.         Q3Group_AddObject(myGroup, myIlluminationShader);
  311.  
  312.         myBoxData.boxAttributeSet = nil;
  313.         myBoxData.faceAttributeSet = nil;
  314.         
  315.         // create the box itself
  316.         Q3Point3D_Set(&myBoxData.origin, 0, 0, 0);
  317.         Q3Vector3D_Set(&myBoxData.orientation, 0, 1, 0);
  318.         Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 1);    
  319.         Q3Vector3D_Set(&myBoxData.minorAxis, 1, 0, 0);    
  320.         myBox = Q3Box_New(&myBoxData);
  321.         
  322.         // put four copies of the box into the group, each one with its own translation
  323.         translation.x = 0;translation.y = 0;translation.z = 0;
  324.         MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  325.     }
  326.     
  327.     TextureGroup( myGroup ) ;
  328.  
  329.     // dispose of the objects we created here
  330.     if( myIlluminationShader ) 
  331.         Q3Object_Dispose(myIlluminationShader);    
  332.                 
  333.     if( myBox ) 
  334.         Q3Object_Dispose( myBox );
  335.     
  336.     //    Done!
  337.     return ( myGroup );
  338. }
  339.  
  340.  
  341.  
  342. //-----------------------------------------------------------------------------------------------
  343. // Submit the scene for rendering/fileIO and picking
  344. TQ3Status SubmitScene( DocumentPtr theDocument ) 
  345. {        
  346.     TQ3Vector3D                globalScale;
  347.     TQ3Vector3D                globalTranslate;
  348.     
  349.     globalScale.x = globalScale.y = globalScale.z = theDocument->fGroupScale;
  350.     globalTranslate = *(TQ3Vector3D *)&theDocument->fGroupCenter;
  351.     Q3Vector3D_Scale(&globalTranslate, -1, &globalTranslate);
  352.     Q3Style_Submit(theDocument->fInterpolation, theDocument->fView);
  353.     Q3Style_Submit(theDocument->fBackFacing , theDocument->fView);
  354.     Q3Style_Submit(theDocument->fFillStyle, theDocument->fView);
  355.         
  356.     Q3MatrixTransform_Submit( &theDocument->fRotation, theDocument->fView);
  357.         
  358.     Q3ScaleTransform_Submit(&globalScale, theDocument->fView);
  359.     Q3TranslateTransform_Submit(&globalTranslate, theDocument->fView);
  360.     Q3DisplayGroup_Submit( theDocument->fModel, theDocument->fView);
  361.     
  362.     return kQ3Success ;
  363. }
  364.  
  365. //-----------------------------------------------------------------------------------------------
  366.  
  367. static TQ3Status GetDocumentGroupBoundingBox( 
  368.     DocumentPtr theDocument , 
  369.     TQ3BoundingBox *viewBBox)
  370. {
  371.     TQ3Status        status;
  372.     TQ3ViewStatus    viewStatus ;
  373.     
  374.     status = Q3View_StartBoundingBox( theDocument->fView, kQ3ComputeBoundsApproximate );
  375.     do {
  376.         status = SubmitScene( theDocument ) ;
  377.     } while((viewStatus = Q3View_EndBoundingBox( theDocument->fView, viewBBox )) == kQ3ViewStatusRetraverse );
  378.     return status ;
  379. }
  380.  
  381.  
  382. //----------------------------------------------------------------------------------
  383. void GetGroupBBox(
  384.     DocumentPtr            theDocument,
  385.     TQ3BoundingBox         *viewBBox)
  386. {
  387.     TQ3Point3D                     from     = { 0.0, 0.0, 1.0 };
  388.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  389.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  390.     
  391.     float                         fieldOfView = .52359333333;
  392.     float                         hither         =  0.5;
  393.     float                         yon         =  1.5;
  394.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  395.  
  396.     TQ3Status                    status;
  397.     
  398. #ifdef BETA_1_BUILD
  399.     Q3View_StartBounds( theDocument->fView );
  400.  
  401.     status = Q3DisplayGroup_BoundingBox(mainGroup, 
  402.                                         viewBBox, 
  403.                                         kQ3ComputeBoundsApproximate,
  404.                                          viewObject);
  405.  
  406.     Q3View_EndBounds( theDocument->fView );
  407. #else
  408.     status = GetDocumentGroupBoundingBox( theDocument , viewBBox) ;
  409. #endif
  410.                                         
  411.     //
  412.     //  If we have a point model, then the "viewBBox" would end up
  413.     //  being a "singularity" at the location of the point.  As
  414.     //  this bounding "box" is used in setting up the camera spec,
  415.     //  we get bogus input into Escher.
  416.     
  417.     {
  418.          float        xSize, ySize, zSize;
  419.         
  420.         xSize = viewBBox->max.x - viewBBox->min.x;
  421.         ySize = viewBBox->max.y - viewBBox->min.y;
  422.         zSize = viewBBox->max.z - viewBBox->min.z;
  423.  
  424.         if (xSize <= kQ3RealZero &&
  425.             ySize <= kQ3RealZero &&
  426.             zSize <= kQ3RealZero) {
  427.             
  428.             viewBBox->max.x += 0.0001;
  429.             viewBBox->max.y += 0.0001;
  430.             viewBBox->max.z += 0.0001;
  431.             
  432.             viewBBox->min.x -= 0.0001;
  433.             viewBBox->min.y -= 0.0001;
  434.             viewBBox->min.z -= 0.0001;
  435.         }
  436.     }
  437. }
  438.  
  439.  
  440.  
  441.  
  442. //------------------------------------------------------------------------
  443.  
  444.  
  445. TQ3Point3D AdjustCamera(
  446.     DocumentPtr            theDocument,
  447.     short                winWidth,
  448.     short                winHeight)
  449. {
  450.     float                         fieldOfView;
  451.     float                         hither;
  452.     float                         yon;
  453.     TQ3CameraPlacement            placement;
  454.     TQ3CameraRange                range;
  455.     TQ3BoundingBox                 viewBBox;
  456.     long                         fromAxis;    
  457.     float                         maxDimension;
  458.      float                        xSize, ySize, zSize;
  459.     float                        weights[2] = { 0.5, 0.5 };
  460.     TQ3Point3D                    points[2];
  461.     TQ3Vector3D                     viewVector;
  462.     TQ3Vector3D                    normViewVector;
  463.     TQ3Vector3D                    eyeToFrontClip;
  464.     TQ3Vector3D                    eyeToBackClip;
  465.     float                        viewDistance;
  466.     TQ3Vector3D                    diagonalVector;
  467.     float                        ratio;
  468.     TQ3CameraObject                camera;
  469.     
  470.     TQ3ViewObject                theView = theDocument->fView ;
  471.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  472.     
  473.     TQ3Point3D                    *documentGroupCenter = &theDocument->fGroupCenter ;
  474.     float                        *documentGroupScale  = &theDocument->fGroupScale ;
  475.  
  476.     Q3View_GetCamera( theView, &camera);
  477.     GetGroupBBox( theDocument, &viewBBox);
  478.  
  479.     /*
  480.      *  If we have a point model, then the "viewBBox" would end up
  481.      *  being a "singularity" at the location of the point.  As
  482.      *  this bounding "box" is used in setting up the camera spec,
  483.      *  we get bogus input into Escher.
  484.      */
  485.     xSize = viewBBox.max.x - viewBBox.min.x;
  486.     ySize = viewBBox.max.y - viewBBox.min.y;
  487.     zSize = viewBBox.max.z - viewBBox.min.z;
  488.  
  489.     if (xSize <= kQ3RealZero &&
  490.         ySize <= kQ3RealZero &&
  491.         zSize <= kQ3RealZero)  {
  492.         viewBBox.max.x += 0.0001;
  493.         viewBBox.max.y += 0.0001;
  494.         viewBBox.max.z += 0.0001;
  495.         
  496.         viewBBox.min.x -= 0.0001;
  497.         viewBBox.min.y -= 0.0001;
  498.         viewBBox.min.z -= 0.0001;
  499.     }
  500.  
  501.     points[0] = viewBBox.min;
  502.     points[1] = viewBBox.max;
  503.  
  504.     Q3Point3D_AffineComb(points, weights, 2, documentGroupCenter);
  505.  
  506.     /*
  507.      *  The "from" point is on a vector perpendicular to the plane
  508.      *  in which the bounding box has greatest dimension.  As "up" is
  509.      *  always in the positive y direction, look at x and z directions.
  510.      */
  511.     xSize = viewBBox.max.x - viewBBox.min.x;
  512.     zSize = viewBBox.max.z - viewBBox.min.z;
  513.     
  514.     if (xSize > zSize) {
  515.         fromAxis = kQ3AxisZ;
  516.     } else {
  517.         fromAxis = kQ3AxisX;
  518.     }
  519.  
  520.     /*
  521.      *  Compute the length of the diagonal of the bounding box.
  522.      *
  523.      *  The hither and yon planes are adjusted so that the
  524.       *  diagonal of the bounding box is 7/8 the size of the
  525.       *  minimum dimension of the view frustum. The diagonal is used instead
  526.       *  of the maximum size (in x, y, or z) so that when you rotate
  527.       *  the object, the corners don't get clipped out.
  528.       */
  529.     Q3Point3D_Subtract(
  530.         &viewBBox.max,
  531.         &viewBBox.min,
  532.         &diagonalVector);
  533.  
  534.     maxDimension    =    Q3Vector3D_Length(&diagonalVector);
  535.     maxDimension    *=    8.0 / 7.0;
  536.     
  537.     ratio = 1.0 / maxDimension;
  538.             
  539.     *documentGroupScale = ratio;
  540.     
  541.     Q3Camera_GetPlacement(camera, &placement);
  542.  
  543.     Q3Point3D_Subtract(
  544.         &placement.cameraLocation,
  545.         &placement.pointOfInterest,
  546.         &viewVector);
  547.         
  548.     viewDistance = Q3Vector3D_Length(&viewVector);
  549.     
  550.     Q3Vector3D_Normalize(&viewVector, &normViewVector);
  551.     
  552.     Q3Vector3D_Scale(&normViewVector, 
  553.                      viewDistance - ratio * maxDimension/2.0,
  554.                      &eyeToFrontClip);
  555.                     
  556.     Q3Vector3D_Scale(&normViewVector, 
  557.                     viewDistance + ratio * maxDimension/2.0,
  558.                     &eyeToBackClip);
  559.  
  560.     hither     = Q3Vector3D_Length(&eyeToFrontClip);
  561.     yon     = Q3Vector3D_Length(&eyeToBackClip);
  562.     
  563.     fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither);
  564.  
  565.     range.hither                 = hither;
  566.     range.yon                     = yon;
  567.  
  568.     Q3Camera_SetRange(camera, &range);
  569.  
  570.     Q3ViewAngleAspectCamera_SetFOV(
  571.         camera, fieldOfView);
  572.  
  573.     Q3ViewAngleAspectCamera_SetAspectRatio(
  574.         camera, (float) winWidth / (float) winHeight);
  575.  
  576.     Q3Object_Dispose(camera);
  577.     
  578.     return( *documentGroupCenter );
  579. }
  580.  
  581.